home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 May: Tool Chest / Dev.CD May 98 TC.toast / Tool Chest / Testing & Debugging / General tools / Report Error 2.0 / ShowStackChain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-17  |  6.2 KB  |  271 lines  |  [TEXT/KAHL]

  1. /*============================================================
  2.     ShowStackChain.c
  3.     
  4.     greggor@apple.com
  5.     
  6.     This package records and displays the current stack
  7.     chain walking the A6 links.  It does not grok every
  8.     possible format of MacsBug symbol names, only the ones
  9.     generated by Think C.
  10.     
  11.     Some modification will be required to get this to
  12.     work with MPW.  (Move 'GetA6' and 'GetSP' into a .a file)
  13. ============================================================*/
  14. #include <Types.h>
  15. #include <Memory.h>
  16. #include <Resources.h>
  17. #include <setjmp.h>
  18.  
  19. #include "ShowStackChain.h"
  20.  
  21. #ifndef __FAILUREHANDLER__
  22. #include "FailureHandler.h"
  23. #endif
  24. #ifndef __MODALSCROLLTEXT__
  25. #include "ModalScrollText.h"
  26. #endif
  27. #ifndef __STRINGUTILITIES__
  28. #include "StringUtilities.h"
  29. #endif
  30.  
  31. #ifndef __SYSEQU__
  32. #include "SysEqu.h"
  33. #endif
  34.  
  35. /*
  36. // Prototypes for routines used privately
  37. */
  38. void PrivateAsmRoutines(void);
  39. void* GetA6(void);
  40. void* GetSP(void);
  41. short GetMacsBugSymName( short* returnAddress, char* where, short maxChars );
  42.  
  43. /*
  44. // Global to stash stack chain durring failure handling
  45. */
  46. StackChainInfo    gFailureStackChain;
  47.  
  48. /*-------------------------------------------------------------------
  49.     Routines that get the value of A6 and A7:
  50. -------------------------------------------------------------------*/
  51. void PrivateAsmRoutines()
  52. {
  53.     asm
  54.     {
  55.     extern GetA6:
  56.     
  57.         move.l        A6,D0
  58.         rts
  59.  
  60.     extern GetSP:
  61.  
  62.         move.l        A7,D0
  63.         rts
  64.     }
  65. }
  66.  
  67. /*-------------------------------------------------------------------
  68.     This function is called during exception handling to
  69.     record the state of the stack frame before it is destroyed
  70.     by longjmp
  71. -------------------------------------------------------------------*/
  72. void RecordStackChain( StackChainInfo* stackChainInfo )
  73. {
  74.     long*        theReturnAddress;
  75.     long*        a6Chain;
  76.     long*        stackTop;
  77.     short        segNum;
  78.     
  79.     stackChainInfo->fEntries = 0;
  80.     /*
  81.     // Walk the stack & record every return address
  82.     // we can find.
  83.     */
  84.     a6Chain = (long*)GetA6();
  85.     stackTop = (long*)GetSP();
  86.     while( (stackChainInfo->fEntries < kMaxStackChainEntries) && (StripAddress(a6Chain) >= StripAddress(stackTop) ) && (StripAddress(a6Chain) <= StripAddress( (void*)(*((long*)CurStackBase))) ) )
  87.     {
  88.         theReturnAddress = (long*) *(a6Chain + 1);
  89.         stackChainInfo->fReturnAddress[stackChainInfo->fEntries++] = theReturnAddress;
  90.         
  91.         a6Chain = (long*)*a6Chain;
  92.     }
  93. }
  94.  
  95. /*-------------------------------------------------------------------
  96.     Copy the MacsBug symbol name associated with the routine
  97.     found at 'returnAddress' into the character string at 'where'
  98. -------------------------------------------------------------------*/
  99. short GetMacsBugSymName( short* returnAddress, char* where, short maxChars )
  100. {
  101.     short*        search;
  102.     short        maxSearch;
  103.     short        offset;
  104.     short        count = 0;
  105.     
  106.     /*
  107.     // We always want to leave at least three characters
  108.     // for the offset into the routine
  109.     */
  110.     maxChars -= 7;
  111.     if( maxChars <= 0 )
  112.         return;
  113.     /*
  114.     // First look for the symbol name
  115.     */
  116.     maxSearch = 0x3FFF;
  117.     search = returnAddress;
  118.     while( maxSearch-- )
  119.     {
  120.         long*    compare = (long*)search;
  121.         
  122.         if( *compare == 0x4E5E4E75 )
  123.         {
  124.             unsigned char*        symName = (unsigned char*)compare;
  125.             short                symLength;
  126.             
  127.             symName += 4;
  128.             
  129.             /*
  130.             // Determine if the symbol name is
  131.             // 8 characters long, 16 characters long,
  132.             // or *symName characters long
  133.             */
  134.             if( (*symName & 0x7F) < 0x20 )
  135.             {
  136.                 symLength = *symName & 0x7F;
  137.                 ++symName;
  138.             }
  139.             else if( *symName >= 0x80 )
  140.             {
  141.                 symLength = 16;
  142.             }
  143.             else
  144.             {
  145.                 symLength = 8;
  146.             }
  147.             
  148.             /*
  149.             // Copy the symbol name into the string
  150.             */
  151.             while( ( (symLength--) > 0 ) && (*symName) && (count < maxChars) )
  152.             {
  153.                 where[count++] = *symName++;
  154.             }
  155.             
  156.             break;
  157.         }
  158.         ++search;
  159.     }
  160.     
  161.     /*
  162.     // If there's no symbol name, don't search for an offset
  163.     */
  164.     if( !count )
  165.         return count;
  166.     
  167.     /*
  168.     // Now look for the 'LNK' instruction
  169.     */
  170.     maxSearch = 0x3FFF;
  171.     search = returnAddress;
  172.     offset = 0;
  173.     while( maxSearch-- )
  174.     {
  175.         if( *search == 0x4E56 )
  176.         {
  177.             where[count++] = ' ';
  178.             where[count++] = '+';
  179.             where[count++] = ' ';
  180.             
  181.             AddHexShortToString( &where[count], offset );
  182.             count += 4;
  183.             
  184.             break;
  185.         }
  186.         --search;
  187.         offset += 2;
  188.     }
  189.     
  190.     return count;
  191. }
  192.  
  193. /*----------------------------------------------------------------------
  194.     Show the specified stack chain
  195. ----------------------------------------------------------------------*/
  196. void ShowStackChain( Str255 title, StackChainInfo* stackChainInfo )
  197. {
  198.     char*        stackText;
  199.     Size        textBufSize;
  200.     #define        kMaxLineLen        40
  201.     
  202.     textBufSize = (stackChainInfo->fEntries * kMaxLineLen) + 4;
  203.     stackText = (char*)NewPtr( textBufSize );
  204.     if( stackText != nil )
  205.     {
  206.         Size        textLen = 0;
  207.         short        i;
  208.         
  209.         for( i=0; i<stackChainInfo->fEntries; ++i )
  210.         {
  211.             short*        returnAddress = stackChainInfo->fReturnAddress[i];
  212.             
  213.             /*
  214.             // Insert the return address and a space into the string
  215.             */
  216.             AddHexLongToString( &stackText[textLen], (long)returnAddress );
  217.             textLen += 8;        
  218.             stackText[textLen++] = ' ';
  219.             /*
  220.             // Insert the macsbug name
  221.             */
  222.             textLen += GetMacsBugSymName( returnAddress, &stackText[textLen], kMaxLineLen - 10 );
  223.             /*
  224.             // Add a CR at the end of the line
  225.             */
  226.             stackText[textLen++] = '\r';
  227.         }
  228.         /*
  229.         // Add on a terminator just for fun (it's not required)
  230.         */
  231.         stackText[textLen++] = 0;
  232.         
  233.         /*
  234.         // We should be cooler than this
  235.         */
  236.         if( textLen > textBufSize )
  237.             DebugStr( "\pTable overflow!" );
  238.         
  239.         ModalScrollText( title, stackText, textLen );
  240.     }
  241. }
  242.  
  243. /*----------------------------------------------------------------------
  244.     Record the stack chain at time of failure (called by failure
  245.     handler)
  246. ----------------------------------------------------------------------*/
  247. void RecordFailureStackChain(void)
  248. {
  249.     RecordStackChain(&gFailureStackChain);
  250. }
  251.  
  252. /*----------------------------------------------------------------------
  253.     Show the stack chain that was recorded at the last failure
  254. ----------------------------------------------------------------------*/
  255. void ShowFailureStackChain(Str255 title)
  256. {
  257.     ShowStackChain(title, &gFailureStackChain);
  258. }
  259.  
  260. /*----------------------------------------------------------------------
  261.     Install 'RecordFailureStackChain' in the failure handler
  262. ----------------------------------------------------------------------*/
  263. void InitShowStackChain()
  264. {
  265.     gFailureStackChain.fEntries = 0;
  266.     SetExceptionNotifyProc((NotifyFailureProc)RecordFailureStackChain);
  267. }
  268.  
  269.  
  270.  
  271.